package de.lmu.mvs.lerngruppenfinder;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageCache;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.Volley;
import com.beardedhen.androidbootstrap.BootstrapCircleThumbnail;
import com.beardedhen.androidbootstrap.BootstrapEditText;
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonObject.Member;
import com.eclipsesource.json.JsonValue;
import com.google.common.io.LineReader;

import de.lmu.mvs.lerngruppenfinder.interests.InterestNode;
import de.lmu.mvs.lerngruppenfinder.interests.InterestTree;
import de.lmu.mvs.lerngruppenfinder.utils.ApplicationController;
import de.lmu.mvs.lerngruppenfinder.utils.BaseActivity;
import de.lmu.mvs.lerngruppenfinder.utils.Constants;
import de.lmu.mvs.lerngruppenfinder.utils.FileApi;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerConnectorListener;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerError;
import de.lmu.mvs.lerngruppenfinder.utils.Utils;
import de.lmu.mvs.lerngruppenfinder.widget.ExpandablePanel;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.drawable.TransitionDrawable;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.support.v4.util.LruCache;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class UserProfileActivity extends BaseActivity {

	private static final String TAG = UserProfileActivity.class.getSimpleName();

	private final String [] items			= new String [] {"Camera", "SD Card"};

	private Uri mImageCaptureUri;
	private static final int PICK_FROM_CAMERA = 1;
	private static final int PICK_FROM_FILE = 2;
	private boolean picChanged = false;
	private boolean interestsChanged = false;
	private boolean passwordChanged = false;

	//private ImageView pPic;	
	private BootstrapCircleThumbnail pPic;

	private RelativeLayout nameTextcontainer;
	private TextView nameText;

	private LinearLayout nameEditcontainer;
	private ImageView nameEditCancel;
	private EditText nameEdit;
	private TextView emailE;

	private BootstrapEditText oldPw;
	private BootstrapEditText newPw;
	private BootstrapEditText repeatPw;

	private Bitmap profilepic;

	private LinearLayout mChangePasswortView;

	private int userID = 37;

	boolean clicked = false;
	boolean nameChanged = false;
	String oldName;

	private LinearLayout mUserInteractionView;

	private LinearLayout mInterestContainer;
	private InterestTree mInterestTree;
	
	/** 
	 * map keeps separate interest arrays for each created view.
	 * Is used to determine which interests have changed after an edit.
	 */
	HashMap<Integer, List<Integer>> mUserInterestsMap = new HashMap<Integer, List<Integer>>();

	/** all interests that the user has */
	private List<Integer> mUserInterests = new ArrayList<Integer>();

	private boolean mUserInteractionVisible = false;
	private boolean mPasswordEditVisible = false;

	// FIXME compare user name in edittext with user name from json
	boolean firstEdit = true;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){
			getActionBar().setDisplayHomeAsUpEnabled(true);
		}
		
		setContentView(R.layout.activity_user_profile);
		
		((TextView)findViewById(R.id.user_interaction_save_changes)).setTypeface(ApplicationController.getTypeFace());

		mChangePasswortView = (LinearLayout) findViewById(R.id.user_password_container);
		((TextView)findViewById(R.id.user_password_image_expander))
			.setTypeface(ApplicationController.getTypeFace());
		oldPw = (BootstrapEditText) findViewById(R.id.oldPw);
		newPw = (BootstrapEditText) findViewById(R.id.newPw);
		repeatPw = (BootstrapEditText) findViewById(R.id.repeatPw);
		
		// show save bar when password is correct
		repeatPw.addTextChangedListener(new TextWatcher() {

			@Override
			public void onTextChanged(CharSequence s, int start, int before, int count) { }

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) { }

			@Override
			public void afterTextChanged(Editable s) { 
				if(!newPw.getText().toString().equals(repeatPw.getText().toString())){
					repeatPw.setTextColor(getResources().getColor(R.color.holo_red_dark));

					hideUserInteraction(false);
				} else {
					repeatPw.setTextColor(oldPw.getTextColors());

					// show when old and new pw have length > 0
					if(oldPw.getText().toString().length() > 0 && newPw.getText().toString().length() > 0){
						showUserInteraction();
						passwordChanged = true;
					}
				}
			}
		});

		nameTextcontainer = (RelativeLayout) findViewById(R.id.name_text_container);
		nameEditcontainer = (LinearLayout) findViewById(R.id.name_edit_container);
		nameEditCancel = (ImageView) findViewById(R.id.name_edit_cancel);
		nameText = (TextView) findViewById(R.id.nameDisplay);
		((TextView)nameTextcontainer.findViewById(R.id.user_name_button_edit)).setTypeface(ApplicationController.getTypeFace());
		
		nameEdit = (EditText) findViewById(R.id.nameEdit);
		nameEdit.addTextChangedListener(new TextWatcher() {

			@Override
			public void onTextChanged(CharSequence s, int start, int before, int count) { }

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) { }

			@Override
			public void afterTextChanged(Editable s) { 
				if(!firstEdit && !mUserInteractionVisible){
					if(!nameText.getText().toString().equals(nameEdit.getText().toString())){
						showUserInteraction();
					}
				}
				firstEdit = false;
			}
		});

		nameTextcontainer.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				nameTextcontainer.setVisibility(View.GONE);
				nameEditcontainer.setVisibility(View.VISIBLE);
				nameEdit.setText(nameText.getText());
				if(nameEdit.requestFocus()) {
				    getWindow().setSoftInputMode(
				    		WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
				}
			}
		});

		nameEditCancel.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if(!interestsChanged && !picChanged){
					hideUserInteraction(false);
				}

				nameTextcontainer.setVisibility(View.VISIBLE);
				nameEditcontainer.setVisibility(View.GONE);
				hideKeyboard();
			}
		});

		emailE = (TextView) findViewById(R.id.emailDisplay);
		//pPic = (ImageView) findViewById(R.id.pPicView);	
		pPic = (BootstrapCircleThumbnail) findViewById(R.id.pPicView);

		mUserInteractionView = (LinearLayout) findViewById(R.id.user_interaction);
		findViewById(R.id.user_interaction_save_changes)
		.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				try {
					sendDataToServer(null);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});

		findViewById(R.id.user_password_change_text).setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if(mPasswordEditVisible){
					hidePasswordEdit();
				} else {
					showPasswordEdit();
				}
			}
		});

		getDataFromServer();

		final ArrayAdapter<String> adapter	= new ArrayAdapter<String> (this, android.R.layout.select_dialog_item,items);
		final AlertDialog.Builder builder	= new AlertDialog.Builder(this);

		pPic.setOnLongClickListener(new View.OnLongClickListener() {        
			@Override
			public boolean onLongClick(View view) {		        	

				builder.setTitle("Select Image");
				builder.setAdapter( adapter, new DialogInterface.OnClickListener() {
					public void onClick( DialogInterface dialog, int item ) {
						if (item == 0) {
							Intent intent 	 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
							File file		 = new File(Environment.getExternalStorageDirectory(),
									"tmp_profile_pic.jpg");
							mImageCaptureUri = Uri.fromFile(file);

							try {
								intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
								intent.putExtra("return-data", true);

								startActivityForResult(intent, PICK_FROM_CAMERA);
							} catch (Exception e) {
								e.printStackTrace();
							}

							dialog.cancel();
						} else {
							Intent intent = new Intent();

							intent.setType("image/*");
							intent.setAction(Intent.ACTION_GET_CONTENT);

							startActivityForResult(Intent.createChooser(intent, "Complete action using"), PICK_FROM_FILE);
						}
					}
				} );

				final AlertDialog dialog = builder.create();	        	

				dialog.show();
				return false;
			}
		});		

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.user_profile, menu);
		return true;
	}


	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// set user interests and update views
		if (requestCode == SetInterestActivity.REQUEST_INTEREST) {
			if (resultCode == RESULT_OK) {
				if(data != null){
					Log.d(TAG, data.getStringExtra(SetInterestActivity.INTEREST_RESULT));

					String interestResult = data.getStringExtra(SetInterestActivity.INTEREST_RESULT).trim();
					int interestEditId = data.getIntExtra(SetInterestActivity.INTERESTS_EDIT_ID, 0);
					if(interestResult != null && interestEditId != 0){

						// create new list with edited userinterests and store in interestmap
						List<Integer> editedInterests = new ArrayList<Integer>(interestResult.split(";").length);
						for (int i = 0; i < interestResult.split(";").length; i++) {
							try {
								editedInterests.add(Integer.parseInt(interestResult.split(";")[i]));
							} catch(NumberFormatException e){
								Log.d(TAG, "Skipped interest id "+interestResult.split(";")[i]+" when converting string result "+interestResult);
							}
						}

						if(editedInterests.size() > 0){
							mUserInterestsMap.put(interestEditId, editedInterests);
						} else {
							mUserInterestsMap.remove(interestEditId);
						}

						// rebuild mUserInterests
						mUserInterests.clear();
						for (Map.Entry<Integer, List<Integer>> entry : mUserInterestsMap.entrySet()) {
							mUserInterests.addAll(entry.getValue());
						}

						//remove duplicates if any
						Set setItems = new LinkedHashSet(mUserInterests);
						mUserInterests.clear();
						mUserInterests.addAll(setItems);

						createInterestViews();
						interestsChanged = true;

						try {
							sendDataToServer(null);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
		} else {

			if (resultCode != RESULT_OK) return;

			Bitmap bitmap 	= null;
			String path		= "";

			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inSampleSize = 2;

			if (requestCode == PICK_FROM_FILE) {
				mImageCaptureUri = data.getData();
				path = Utils.getPath(this, mImageCaptureUri);
				if (path == null)
					path = mImageCaptureUri.getPath(); 
				if (path != null)
					bitmap 	= BitmapFactory.decodeFile(path, options);				
			} 
			else {
				path	= mImageCaptureUri.getPath();
				bitmap = BitmapFactory.decodeFile(path, options);
			}

			int orientation = 0;
			Matrix matrix = new Matrix();

			try {
				ExifInterface exif = new ExifInterface(path);
				orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
				switch (orientation) {
				case 3 :
					matrix.postRotate(180);
					break;
				case 6 :
					matrix.postRotate(90);
					break;
				case 8 :
					matrix.postRotate(270);
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			if(bitmap != null){
				profilepic = Bitmap.createBitmap(bitmap, 0, 0,bitmap.getWidth(), bitmap.getHeight(), matrix, true);
	//			pPic.setImageBitmap(profilepic);
				pPic.setImage(profilepic);
				picChanged = true;
				Log.d(TAG, "change pic");
				showUserInteraction();
			}
		}
	}
	
	public void writeUserDetails(JsonObject json){
		for( Member member : json ) {
			String name = member.getName();
			JsonValue value = member.getValue();
			if (name.equals("mail"))
				emailE.setText(value.toString().substring(1, value.toString().length()-1));

			if (name.equals("name"))
			{
				oldName = value.toString().substring(1, value.toString().length()-1);
				nameText.setText(oldName);
				nameEdit.setText(oldName);
			}						
			if (name.equals("bild"))	
			{
				final String url1 = value.toString().substring(1, value.toString().length()-1);								
				ImageLoader imageLoader = ApplicationController.getInstance().getImageLoader();
				imageLoader.get(url1, new ImageLoader.ImageListener() {
			        
					@Override
			        public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
						if(response.getBitmap() != null){
							pPic.setImage(response.getBitmap());
						} else {
							Log.e(TAG, "No image found at " + url1);
						}
						
			        }

			        @Override
			        public void onErrorResponse(VolleyError error) {
			        	Log.e(TAG, error.getLocalizedMessage());
			        }
			    });
				
			}
			if (name.equals("id")){
				userID=Integer.parseInt(value.toString().substring(1, value.toString().length()-1));
			}
		}

		setupInterests();
	}
	
	public void getDataFromServer(){	

		JsonObject user = FileApi.readJsonFromStorage("UserCredentials", UserProfileActivity.this).asObject();
		if(user == null){
			ServerConnector.getUserById(new ServerConnectorListener<JsonObject>() {

				@Override
				public void requestFinished(JsonObject json) {
					writeUserDetails(json);
				}

				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
				}
			}, FileApi.readLoginCredentials().id);
		} else {
			writeUserDetails(user);
		}
	}

	public void sendDataToServer(View view) throws IOException{

		String newName = nameEdit.getText().toString();

		if (oldName != null && !oldName.equals(newName))
			nameChanged = true;
		
		if(oldName == null){
			nameChanged = true;
		}

		if (picChanged)
		{
			String filename = "profilePic" + Integer.toString(userID) + ".png";

			File f =  new File(getBaseContext().getCacheDir(), filename);
			f.createNewFile();

			//Convert bitmap to byte array
			/* 
		pPic.setDrawingCacheEnabled(true);
		 pPic.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
		                   MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
		 pPic.layout(0, 0, pPic.getMeasuredWidth(),  pPic.getMeasuredHeight()); 
		 pPic.buildDrawingCache(true);
		 Bitmap bitmap = Bitmap.createBitmap( pPic.getDrawingCache());
		 pPic.setDrawingCacheEnabled(false);
			 */
			Bitmap bitmap = profilepic;
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			bitmap.compress(CompressFormat.PNG, 0 , bos);
			byte[] bitmapdata = bos.toByteArray();

			//write the bytes in file
			@SuppressWarnings("resource")
			FileOutputStream fos = new FileOutputStream(f);
			fos.write(bitmapdata);

			ServerConnector.uploadProfilePicture(new ServerConnectorListener<JsonObject>() {

				@Override
				public void requestFinished(JsonObject json) {
					hideUserInteraction(false);
					hideKeyboard();
					ServerConnector.getUserById(new ServerConnectorListener<JsonObject>() {

						@Override
						public void requestFinished(JsonObject json) {
							// TODO Auto-generated method stub
							try {
								FileApi.writeJsonToStorage(json, "UserCredentials", UserProfileActivity.this);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}

						@Override
						public void requestError(ServerError error) {
							// TODO Auto-generated method stub
							
						}
					}, userID);
					showToast(R.string.toast_pic_saved);
				}
				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
				}

			}, userID, f);

			fos.close();
		}
		if (nameChanged)
		{
			ServerConnector.changeUserName(new ServerConnectorListener<JsonObject>() {

				@Override
				public void requestFinished(JsonObject json) {
					hideUserInteraction(false);
					hideKeyboard();
					ServerConnector.getUserById(new ServerConnectorListener<JsonObject>() {

						@Override
						public void requestFinished(JsonObject json) {
							// TODO Auto-generated method stub
							try {
								FileApi.writeJsonToStorage(json, "UserCredentials", UserProfileActivity.this);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}

						@Override
						public void requestError(ServerError error) {
							// TODO Auto-generated method stub
							
						}
					}, userID);
					showToast(R.string.toast_name_saved);
				}

				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
				}
			}, userID, newName);	

		}

		if(interestsChanged){
			ServerConnector.setUserInterests(new ServerConnectorListener<JsonArray>() {

				@Override
				public void requestFinished(JsonArray json) {
					hideUserInteraction(false);
					hideKeyboard();
					showToast(R.string.toast_interests_saved);
				}

				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
				}
			}, userID, mUserInterests);
		}
		
		if(passwordChanged){
			if (TextUtils.isEmpty(newPw.getText().toString())) {
				newPw.setError(getString(R.string.error_field_required));
				newPw.requestFocus();
			} else if (newPw.getText().toString().length() < 4) {
				newPw.setError(getString(R.string.error_invalid_password));
				newPw.requestFocus();
			}
			
			ServerConnector.changeUserPassword(new ServerConnectorListener<JsonObject>() {

				@Override
				public void requestFinished(JsonObject json) {
					hideUserInteraction(false);
					hidePasswordEdit();
					hideKeyboard();
					showToast(R.string.toast_password_changed);
				}

				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
					hideUserInteraction(true);
					showToast(R.string.toast_password_changed_error);
					
				}
			}, userID, oldPw.getText().toString(), newPw.getText().toString());
		}
		
		nameChanged = false;
		picChanged = false;
		passwordChanged = false;
		interestsChanged = false;
	}

	/**
	 * Get interests from storage or server and initiate views
	 */
	private void setupInterests(){
		mInterestContainer = (LinearLayout) findViewById(R.id.interest_container);

		//FIXME get user id and request user interests from server
		ServerConnector.getUserInterests(new ServerConnectorListener<JsonArray>() {

			@Override
			public void requestFinished(JsonArray json) {
				if(json.isArray()){
					mUserInterests.clear();
					for (int i = 0; i < json.size(); i++) {
						mUserInterests.add(Integer.parseInt(
								json.asArray().get(i).asObject().get(Constants.JSON_INTEREST_ID).asString()));
					}
					// if the other one finished first, create interest text views
					if(mInterestTree != null){
						createInterestViews();
					}
				}
			}
			@Override
			public void requestError(ServerError error) {
				Log.e(TAG, error.getErrorMessage());
			}
		}, userID);

		// load interest tree
		JsonValue interestJson;
		Log.i(TAG, "Try loading interests from storage...");
		if((interestJson = FileApi.readJsonFromStorage("interests", this)) != null){
			if(interestJson.isArray()){
				mInterestTree = new InterestTree(interestJson.asArray());
				// if the other one finished first, create interest text views
				if(mUserInterests != null){
					createInterestViews();
				}
			}
		} else {
			// get list from server
			Log.i(TAG, "No files in storage available, try loading interests from server...");
			ServerConnector.getInterests(new ServerConnectorListener<JsonArray>() {

				@Override
				public void requestFinished(JsonArray json) {
					mInterestTree = new InterestTree(json);
					// if the other one finished first, create interest text views
					if(mUserInterests != null){
						createInterestViews();
					}
				}
				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
					Toast.makeText(getBaseContext(), "Error loading filters", Toast.LENGTH_LONG).show();
				}
			});
		}
	}

	@SuppressLint("UseSparseArrays")
	private void createInterestViews(){
		Log.d(TAG, "Create interest views...");

		/*
		 * first: as we only have the ids as an array we have to sort our which id
		 * is parent of which and how many views we are creating eventually.
		 * for every parent id we create one view with all its children attached.
		 * every parents has its own InterestTree. -> performance is not so important here
		 */

		// true := is parent; false := is child
		HashMap<Integer, Boolean> idMap = new HashMap<Integer, Boolean>();
		HashMap<Integer, InterestTree> interestTrees = new HashMap<Integer, InterestTree>();

		for (Integer interestId : mUserInterests) {
			InterestNode current = mInterestTree.find(interestId);
			if(current != null){
				idMap.put(interestId, !current.isLeaf());
			}
		}

		// create interest tree for every parent and sort our relations
		for (Map.Entry<Integer, Boolean> entry : idMap.entrySet()) {
			if(entry.getValue() && !interestTrees.containsKey(entry.getKey())){
				// if id is parent create new interest tree
				interestTrees.put(
						entry.getKey(), 
						new InterestTree(mInterestTree.find(entry.getKey()).copyNodeOnly()));
			} else if(!entry.getValue()) {
				//if id child add child to existing interest tree or create new interest tree if parent isnt already stored
				InterestNode child = mInterestTree.find(entry.getKey());
				if(child == null){
					continue; // skip if null
				}

				InterestNode parent = child.getParent();
				if(parent != null && !interestTrees.containsKey(parent.getInterestId())){
					// create new tree if parent doesnt already exist
					interestTrees.put(
							parent.getInterestId(), 
							new InterestTree(mInterestTree.find(parent.getInterestId()).copyNodeOnly()));
				}

				if(parent != null && interestTrees.containsKey(parent.getInterestId())){
					// parents exists and we add the child to the parent
					interestTrees.get(parent.getInterestId()).root
					.addChildren(child.copyNodeOnly());
				}
			}
		}

		// create views
		mUserInterestsMap.clear();
		mInterestContainer.removeAllViews();
		for (Map.Entry<Integer, InterestTree> entry : interestTrees.entrySet()) {
			final int tag = (int) System.currentTimeMillis();
			final InterestTree tree = entry.getValue();

			ExpandablePanel interestPanel = (ExpandablePanel) LayoutInflater.from(this).inflate(R.layout.interest_user_parent, null);
			((TextView) interestPanel.findViewById(R.id.interest_title)).setText(tree.root.getInterestName());

			// set edit button listener
			((TextView)interestPanel.findViewById(R.id.interest_edit)).setTypeface(ApplicationController.getTypeFace());
			interestPanel.findViewById(R.id.interest_edit).setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View arg0) {
					Intent interestIntent = new Intent(getBaseContext(), SetInterestActivity.class);
					interestIntent.putExtra(SetInterestActivity.INTERESTS_EDIT_ID, tag);

					String selectedIds = "";
					for (int i = 0; i < tree.getAllInterests().size(); i++) {
						selectedIds += tree.getAllInterests().get(i);
						if(i < tree.getAllInterests().size() - 1){
							selectedIds += ";";
						}
					}

					interestIntent.putExtra(SetInterestActivity.SELECTED_IDS, selectedIds);
					startActivityForResult(interestIntent, SetInterestActivity.REQUEST_INTEREST);
				}
			});

			for (InterestNode child : tree.root.getChildren()) {
				TextView childInterest = (TextView) LayoutInflater.from(this).inflate(R.layout.interest_user_child, null);
				childInterest.setText(child.getInterestName());
				((LinearLayout)interestPanel.findViewById(R.id.interest_children_conainer)).setVisibility(View.VISIBLE);
				((LinearLayout)interestPanel.findViewById(R.id.interest_children_conainer)).addView(childInterest);
			}


			// add tree ids to map to store separate interests
			mUserInterestsMap.put(tag, tree.getAllInterests());

			interestPanel.setHandleId(R.id.interest_title);
			interestPanel.setTag(tag); // set unique tag
			mInterestContainer.addView(interestPanel);
		}

		// add a button to add new interests
		View addInterestView = LayoutInflater.from(this).inflate(R.layout.interest_add_new, null);
		((TextView)addInterestView.findViewById(R.id.button_add)).setTypeface(ApplicationController.getTypeFace());
		addInterestView.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent interestIntent = new Intent(getBaseContext(), SetInterestActivity.class);
				interestIntent.putExtra(SetInterestActivity.INTERESTS_EDIT_ID, (int) System.currentTimeMillis());
				startActivityForResult(interestIntent, SetInterestActivity.REQUEST_INTEREST);
			}
		});
		mInterestContainer.addView(addInterestView);
	}

	@SuppressLint("NewApi")
	private void showPasswordEdit(){
		mPasswordEditVisible = true;

		if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
			mChangePasswortView.setVisibility(View.VISIBLE);

			oldPw.setText("");
			newPw.setText("");
			repeatPw.setText("");

			((TextView) findViewById(R.id.user_password_image_expander)).setText(R.string.fa_angle_double_up);

			final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
			final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
			mChangePasswortView.measure(widthSpec, heightSpec);

			slideAnimator(250, 0, mChangePasswortView.getMeasuredHeight(), mChangePasswortView).start();
		} else {
			mChangePasswortView.setVisibility(View.VISIBLE);
		}
	}

	/**
	 * hide view with user interaction "save changes"
	 */
	@SuppressLint("NewApi")
	private void hidePasswordEdit(){
		runOnUiThread(new Runnable() {
			
			@Override
			public void run() {
				mPasswordEditVisible = false;
				hideKeyboard();

				if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
					((TextView) findViewById(R.id.user_password_image_expander)).setText(R.string.fa_angle_double_down);

					int finalHeight = mChangePasswortView.getHeight();
					ValueAnimator mAnimator = slideAnimator(250, finalHeight, 0, mChangePasswortView);
					mAnimator.addListener(new Animator.AnimatorListener() {
						@Override
						public void onAnimationEnd(Animator animator) {
							mChangePasswortView.setVisibility(View.GONE);
						}

						@Override
						public void onAnimationCancel(Animator arg0) {}

						@SuppressLint("NewApi")
						@Override
						public void onAnimationRepeat(Animator arg0) {}

						@Override
						public void onAnimationStart(Animator arg0) {}
					});
					mAnimator.start();
				} else {
					mUserInteractionView.setVisibility(View.GONE);
				}
			}
		});
	}

	/**
	 * Show view with user interaction "save changes"
	 */
	@SuppressLint("NewApi")
	private void showUserInteraction(){
		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				mUserInteractionVisible = true;

				// reset background
				mUserInteractionView.setBackground(getResources()
						.getDrawable(R.drawable.user_interaction_transition_orange_green));

				if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
					mUserInteractionView.setVisibility(View.VISIBLE);

					ValueAnimator mAnimator = slideAnimator(250, 0,
							(int) getResources().getDimension(R.dimen.item_userinteraction), mUserInteractionView);
					mAnimator.start();
				} else {
					mUserInteractionView.setVisibility(View.VISIBLE);
				}
			}
		});
	}

	/**
	 * hide view with user interaction "save changes"
	 */
	@SuppressLint("NewApi")
	private void hideUserInteraction(final boolean error){
		runOnUiThread(new Runnable() {
			
			@Override
			public void run() {
				mUserInteractionVisible = false;

				if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
					if(!error){
						transitionToSaved();
					} else {
						transitionToCancel();
					}

					int finalHeight = mUserInteractionView.getHeight();

					ValueAnimator mAnimator = slideAnimator(250, finalHeight, 0, mUserInteractionView);

					mAnimator.addListener(new Animator.AnimatorListener() {
						@Override
						public void onAnimationEnd(Animator animator) {
							mUserInteractionView.setVisibility(View.GONE);

							if(nameChanged){
								nameTextcontainer.setVisibility(View.VISIBLE);
								nameText.setText(nameEdit.getText());

								nameEditcontainer.setVisibility(View.GONE);
							}
						}

						@Override
						public void onAnimationCancel(Animator arg0) {}

						@SuppressLint("NewApi")
						@Override
						public void onAnimationRepeat(Animator arg0) {}

						@Override
						public void onAnimationStart(Animator arg0) {}
					});
					mAnimator.start();
				} else {
					mUserInteractionView.setVisibility(View.GONE);
				}
			}
		});
	}

	private void transitionToSaved(){
		findViewById(R.id.user_interaction)
			.setBackground(getResources().getDrawable(R.drawable.user_interaction_transition_orange_green));
		((TransitionDrawable) findViewById(R.id.user_interaction)
				.getBackground()).startTransition(250);
	}
	
	private void transitionToCancel(){
		findViewById(R.id.user_interaction)
			.setBackground(getResources().getDrawable(R.drawable.user_interaction_transition_orange_red));
		((TransitionDrawable) findViewById(R.id.user_interaction)
				.getBackground()).startTransition(100);
	}

	@SuppressLint("NewApi")
	private ValueAnimator slideAnimator(long duration, int start, int end, final View view) {

		ValueAnimator animator = ValueAnimator.ofInt(start, end);
		animator.setDuration(duration);
		animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

			@SuppressLint("NewApi")
			@Override
			public void onAnimationUpdate(ValueAnimator valueAnimator) {
				//Update Height
				int value = (Integer) valueAnimator.getAnimatedValue();
				ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
				layoutParams.height = value;
				view.setLayoutParams(layoutParams);
			}
		});
		return animator;
	}
	
	private void showToast(final int string){
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				Toast.makeText(getBaseContext(), getString(string), Toast.LENGTH_LONG).show();
			}
		});
	}

	private void hideKeyboard(){
		if(this.getCurrentFocus() != null){
			InputMethodManager inputManager = 
					(InputMethodManager) this.
					getSystemService(Context.INPUT_METHOD_SERVICE); 
			inputManager.hideSoftInputFromWindow(
					this.getCurrentFocus().getWindowToken(),
					InputMethodManager.HIDE_NOT_ALWAYS);
		}
	}
	
	private void updateUserData(){
		ServerConnector.getUserById(new ServerConnectorListener<JsonObject>() {

			@Override
			public void requestFinished(JsonObject json) {
				try {
					FileApi.writeJsonToStorage(json, Constants.USER_CREDENTIALS, (Activity)getBaseContext());
					getDataFromServer();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			@Override
			public void requestError(ServerError error) {
				Log.e(TAG, error.getErrorMessage());
			}
		}, userID);
	}
}
